#include "Inf_LCD.h"

#include "lCD_font.h"
#include "math.h"

#define PI 3.14
void Inf_LCD_Reset(void)
{
    GPIOG->ODR &= ~GPIO_ODR_ODR15;
    HAL_Delay(100);
    GPIOG->ODR |= GPIO_ODR_ODR15;
}
// 开启背光
void Inf_LCD_BKON(void)
{
    GPIOB->ODR |= GPIO_ODR_ODR0;
}
// 关闭背光
void Inf_LCD_BKOFF(void)
{
    GPIOB->ODR &= ~GPIO_ODR_ODR0;
}
/// @brief 发送控制数据
/// @param cmd
void Inf_LCD_WriteCmd(uint16_t cmd)
{
    *LCD_ADDR_CMD = cmd;
}

/// @brief 发送显示数据
/// @param data
void Inf_LCD_WriteData(uint16_t data)
{
    *LCD_ADDR_DATA = data;
}
uint16_t Inf_LCD_ReadData(void)
{
    return *LCD_ADDR_DATA;
}

void Inf_LCD_RegConfig(void);

void Inf_LCD_Init(void)
{
    Inf_LCD_Reset();
    Inf_LCD_BKON();
    Inf_LCD_RegConfig();
}

/// @brief 设置显示区域
/// @param y 起始行
/// @param x 起始列
/// @param w 显示宽度 max x+w=320
/// @param h 显示高度 max y+h=480
void Inf_LCD_SetArea(uint16_t y, uint16_t x, uint16_t w, uint16_t h)
{
    Inf_LCD_WriteCmd(0x2a); // 设置列
    /* 开始列 */
    Inf_LCD_WriteData(x >> 8); // 先发高八位
    Inf_LCD_WriteData(x);      // 再发低八位
    /* 结束列 */
    Inf_LCD_WriteData((x + w - 1) >> 8); // 先发高八位
    Inf_LCD_WriteData(x + w - 1);        // 再发低八位

    Inf_LCD_WriteCmd(0x2b); // 设置行
    /* 开始行 */
    Inf_LCD_WriteData((y) >> 8);
    Inf_LCD_WriteData(y);
    /* 结束行 */
    Inf_LCD_WriteData((y + h - 1) >> 8);
    Inf_LCD_WriteData(y + h - 1);
}

void Inf_LCD_ClearAll(uint16_t color)
{
    Inf_LCD_SetArea(0, 0, DISPLAY_W, DISPLAY_H);
    Inf_LCD_WriteCmd(0x2c);
    for (uint32_t i = 0; i < DISPLAY_H * DISPLAY_W; i++)
    {
        Inf_LCD_WriteData(color);
    }
}

/// @brief 根据字体大小获取对应大小字模的一行像素
/// @param index 字体字模在数组中角标（按ascii顺序
/// @param line 行号
/// @param width 字体宽度 6/8/12/16
/// @return 字模的一行像素
static uint16_t Inf_LCD_GetFontBySize(uint8_t index, uint8_t line, uint8_t width)
{
    switch (width)
    {
    case 6:
        return ascii_1206[index][line];
    case 8:
        return ascii_1608[index][line];
    case 12:
        /* 字模的取模走向是逆向 低位在前，但保存的字模数据是每个字节高位在前，宽度为12位占两个字节
        且后八位高于前八位，要把字模的两个八位数据转为一个16位且高位在前的数据 */
        return (ascii_2412[index][line * 2 + 1] << 8) | ascii_2412[index][line * 2];
    default:
        return (ascii_3216[index][line * 2 + 1] << 8) | ascii_3216[index][line * 2];
    }
}

void Inf_LCD_ShowChar(uint16_t y, uint16_t x, uint8_t c, uint16_t width, uint16_t fontColor, uint16_t backColor)
{
    // 设置字体显示区域[英文字符和数字 高度是宽度的2倍]
    Inf_LCD_SetArea(y, x, width, width * 2);
    // 发送写数据到内存的指令
    Inf_LCD_WriteCmd(0x2c);
    // 获取字体字模在数组中角标(ASCII)
    uint8_t index = c - ' ';
    // 遍历每一行字模,填充颜色
    for (uint8_t i = 0; i < width * 2; i++)
    {
        uint16_t font = Inf_LCD_GetFontBySize(index, i, width);
        for (uint8_t i = 0; i < width; i++)
        {
            if (font & 0x01)
            {
                Inf_LCD_WriteData(fontColor);
            }
            else
            {
                Inf_LCD_WriteData(backColor);
            }
            font >>= 1; // 像素显示低位在前
        }
    }
}

void Inf_LCD_ShowString(uint16_t y, uint16_t x, uint8_t *str, uint16_t len, uint16_t width, uint16_t fontColor, uint16_t backColor)
{
    for (uint16_t i = 0; i < len; i++)
    {
        if (x + width > DISPLAY_W)
        {
            y += width * 2;
            x = 0;
        }

        Inf_LCD_ShowChar(y, x, str[i], width, fontColor, backColor);
        x += width;
    }
}

void Inf_LCD_ShowChineseChar(uint16_t y, uint16_t x, uint8_t index, uint16_t fontColor, uint16_t backColor)
{

    Inf_LCD_SetArea(y, x, 32, 32);
    Inf_LCD_WriteCmd(0x2c);

    for (uint8_t i = 0; i < 32; i++)
    {
        uint32_t font = (chinese[index][i * 4 + 3] << 24) | (chinese[index][i * 4 + 2] << 16) | (chinese[index][i * 4 + 1] << 8) | (chinese[index][i * 4]);
        for (uint8_t i = 0; i < 32; i++)
        {
            if (font & 0x0001)
            {
                Inf_LCD_WriteData(fontColor);
            }
            else
            {
                Inf_LCD_WriteData(backColor);
            }
            font >>= 1;
        }
    }
}

void Inf_LCD_ShowChineseString(uint16_t y, uint16_t x, uint8_t index, uint8_t len, uint16_t fontColor, uint16_t backColor)
{
    for (uint8_t i = 0; i < len; i++)
    {
        if (x + 32 > DISPLAY_W)
        {
            x = 0;
            y += 32;
        }
        Inf_LCD_ShowChineseChar(y, x, index + i, fontColor, backColor);
        x += 32;
    }
}

void Inf_LCD_DrawPoint(uint16_t y, uint16_t x, uint16_t width, uint16_t color)
{
    Inf_LCD_SetArea(y, x, width, width);
    Inf_LCD_WriteCmd(0x2c);
    for (uint16_t i = 0; i < width * width; i++) // 显示区域内像素点从左到右从上到下刷新
    {
        Inf_LCD_WriteData(color);
    }
}

/* void Inf_LCD_ShowImg(void)
{
    Inf_LCD_SetArea(0,0,DISPLAY_W,DISPLAY_H);
    Inf_LCD_WriteCmd(0x2c);
    //图片像素高位在前 两个字节表示一个彩色像素
    for (uint32_t i = 0; i < sizeof(gImage_gbl); i+=2)
    {
        Inf_LCD_WriteData((gImage_gbl[i]<<8)|gImage_gbl[i+1]);
    }

}
 */

void Inf_LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t width, uint16_t color)
{
    uint16_t y_min = y1 > y2 ? y2 : y1;
    uint16_t y_max = y1 > y2 ? y1 : y2;
    uint16_t x_min = x1 > x2 ? x2 : x1;
    uint16_t x_max = x1 > x2 ? x1 : x2;

    if (x1 == x2) // 竖线无法算斜率
    {
        for (uint16_t y = y_min; y <= y_max; y++)
        {
            Inf_LCD_DrawPoint(y, x1, width, color);
        }
    }
    else
    {
        double k, b;
        k = (y2 - y1) * 1.0 / (x2 - x1);
        b = y1 - k * x1;
        for (uint16_t x = x_min; x <= x_max; x++)
        {
            Inf_LCD_DrawPoint(k * x + b, x, width, color);
        }
    }
}
void Inf_LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, uint16_t width, uint16_t color)
{
    Inf_LCD_DrawLine(y1, x1, y1, x2, width, color);
    Inf_LCD_DrawLine(y2, x1, y2, x2, width, color);
    Inf_LCD_DrawLine(y1, x1, y2, x1, width, color);
    Inf_LCD_DrawLine(y1, x2, y2, x2, width, color);
}
void Inf_LCD_DrawRound(uint16_t x, uint16_t y, uint8_t r, uint16_t width, uint16_t color)
{
    /* //速度较慢
   for(uint16_t i=0;i<=360;i++){

       uint16_t x1 = x + r * cos( i * PI / 180 );
       uint16_t y1 = y+ r * sin( i * PI / 180 );

       Inf_LCD_DrawPoint(x1,y1,width,color);
    } */
    for (uint8_t i = 0; i < 90; i++)
    {
        /* // 第一象限
         x1=x+r*cos((i/90)*(PI/2));//极坐标
         y1=y+r*sin((i/90)*(PI/2));
        // 第二象限
         x2=x-r*cos((i/90)*(PI/2));//极坐标
         y2=y+r*sin((i/90)*(PI/2));
        // 第三象限
         x3=x-r*cos((i/90)*(PI/2));//极坐标
         y3=y-r*sin((i/90)*(PI/2));
        // 第四象限
         x4=x+r*cos((i/90)*(PI/2));//极坐标
         y4=y-r*sin((i/90)*(PI/2));
         */

        uint16_t x1 = x + r * cos(i*PI/180); // 极坐标
        uint16_t y1 = y + r * sin(i*PI/180);
        Inf_LCD_DrawPoint(y1, x1, width, color); // 第一象限
        // 圆的对称性
        Inf_LCD_DrawPoint(y1, 2 * x - x1, width, color);         // 第二象限
        Inf_LCD_DrawPoint(2 * y - y1, 2 * x - x1, width, color); // 第三象限
        Inf_LCD_DrawPoint(2 * y - y1, x1, width, color);         // 第四象限
    }
}
void Inf_LCD_DrawSolidCircle(uint16_t x, uint16_t y, uint8_t r, uint16_t width, uint16_t color)
{
    // 大圆套小圆
    /*  for (uint8_t i = 0; i < r; i++)
     {
         Inf_LCD_DrawRound(y,x,i,width,color);
     } */

    // 用圆上下两端的线填充
    for (uint8_t i = 0; i < 90; i++)
    {
        uint16_t x1 = x + r * cos(i*PI/180); // 极坐标
        uint16_t y1 = y + r * sin(i*PI/180);
        Inf_LCD_DrawLine(y1,x1,2*y-y1,x1,width,color);
        Inf_LCD_DrawLine(y1,x*2-x1,2*y-y1,x*2-x1,width,color);
    }
}
/* 初始化寄存器的值 */
void Inf_LCD_RegConfig(void)
{
    /* 1. 设置灰阶电压以调整TFT面板的伽马特性， 正校准。一般出厂就设置好了 */
    Inf_LCD_WriteCmd(0xE0);
    Inf_LCD_WriteData(0x00);
    Inf_LCD_WriteData(0x07);
    Inf_LCD_WriteData(0x10);
    Inf_LCD_WriteData(0x09);
    Inf_LCD_WriteData(0x17);
    Inf_LCD_WriteData(0x0B);
    Inf_LCD_WriteData(0x41);
    Inf_LCD_WriteData(0x89);
    Inf_LCD_WriteData(0x4B);
    Inf_LCD_WriteData(0x0A);
    Inf_LCD_WriteData(0x0C);
    Inf_LCD_WriteData(0x0E);
    Inf_LCD_WriteData(0x18);
    Inf_LCD_WriteData(0x1B);
    Inf_LCD_WriteData(0x0F);

    /* 2. 设置灰阶电压以调整TFT面板的伽马特性，负校准 */
    Inf_LCD_WriteCmd(0XE1);
    Inf_LCD_WriteData(0x00);
    Inf_LCD_WriteData(0x17);
    Inf_LCD_WriteData(0x1A);
    Inf_LCD_WriteData(0x04);
    Inf_LCD_WriteData(0x0E);
    Inf_LCD_WriteData(0x06);
    Inf_LCD_WriteData(0x2F);
    Inf_LCD_WriteData(0x45);
    Inf_LCD_WriteData(0x43);
    Inf_LCD_WriteData(0x02);
    Inf_LCD_WriteData(0x0A);
    Inf_LCD_WriteData(0x09);
    Inf_LCD_WriteData(0x32);
    Inf_LCD_WriteData(0x36);
    Inf_LCD_WriteData(0x0F);

    /* 3.  Adjust Control 3 (F7h)  */
    /*LCD_WriteCmd(0XF7);
    Inf_LCD_WriteData(0xA9);
    Inf_LCD_WriteData(0x51);
    Inf_LCD_WriteData(0x2C);
    Inf_LCD_WriteData(0x82);*/
    /* DSI write DCS command, use loose packet RGB 666 */

    /* 4. 电源控制1*/
    Inf_LCD_WriteCmd(0xC0);
    Inf_LCD_WriteData(0x11); /* 正伽马电压 */
    Inf_LCD_WriteData(0x09); /* 负伽马电压 */

    /* 5. 电源控制2 */
    Inf_LCD_WriteCmd(0xC1);
    Inf_LCD_WriteData(0x02);
    Inf_LCD_WriteData(0x03);

    /* 6. VCOM控制 */
    Inf_LCD_WriteCmd(0XC5);
    Inf_LCD_WriteData(0x00);
    Inf_LCD_WriteData(0x0A);
    Inf_LCD_WriteData(0x80);

    /* 7. Frame Rate Control (In Normal Mode/Full Colors) (B1h) */
    Inf_LCD_WriteCmd(0xB1);
    Inf_LCD_WriteData(0xB0);
    Inf_LCD_WriteData(0x11);

    /* 8.  Display Inversion Control (B4h) （正负电压反转，减少电磁干扰）*/
    Inf_LCD_WriteCmd(0xB4);
    Inf_LCD_WriteData(0x02);

    /* 9.  Display Function Control (B6h)  */
    Inf_LCD_WriteCmd(0xB6);
    Inf_LCD_WriteData(0x0A);
    Inf_LCD_WriteData(0xA2);

    /* 10. Entry Mode Set (B7h)  */
    Inf_LCD_WriteCmd(0xB7);
    Inf_LCD_WriteData(0xc6);

    /* 11. HS Lanes Control (BEh) */
    Inf_LCD_WriteCmd(0xBE);
    Inf_LCD_WriteData(0x00);
    Inf_LCD_WriteData(0x04);

    /* 12.  Interface Pixel Format (3Ah) */
    Inf_LCD_WriteCmd(0x3A);
    Inf_LCD_WriteData(0x55); /* 0x55 : 16 bits/pixel  */

    /* 13. Sleep Out (11h) 关闭休眠模式 */
    Inf_LCD_WriteCmd(0x11);

    /* 14. 设置屏幕方向和RGB */
    Inf_LCD_WriteCmd(0x36);
    Inf_LCD_WriteData(0x08);

    HAL_Delay(120);

    /* 14. display on */
    Inf_LCD_WriteCmd(0x29);
}
